"""
API端点集成测试
==============

测试所有REST API端点的完整集成，包括认证、错误处理、业务流程
"""

import pytest
import asyncio
from unittest.mock import AsyncMock, MagicMock, patch
from datetime import datetime, timezone
from decimal import Decimal
import json

try:
    from fastapi.testclient import TestClient
    from fastapi import FastAPI, HTTPException, status
    import httpx
    API_FRAMEWORK_AVAILABLE = True
except ImportError:
    API_FRAMEWORK_AVAILABLE = False


@pytest.mark.integration
@pytest.mark.api
class TestMarketDataAPI:
    """市场数据API端点测试"""
    
    @pytest.fixture
    def mock_fastapi_app(self):
        """创建Mock FastAPI应用"""
        if not API_FRAMEWORK_AVAILABLE:
            pytest.skip("FastAPI not available")
        
        app = FastAPI(title="Market Data Service Test")
        
        # Mock数据存储
        mock_data = {
            "AAPL": {
                "symbol": "AAPL",
                "price": 150.25,
                "volume": 1000000,
                "timestamp": "2024-01-01T10:00:00Z"
            },
            "GOOGL": {
                "symbol": "GOOGL", 
                "price": 2800.50,
                "volume": 500000,
                "timestamp": "2024-01-01T10:00:00Z"
            }
        }
        
        @app.get("/api/v1/market-data/{symbol}")
        async def get_market_data(symbol: str):
            """获取市场数据"""
            if symbol.upper() in mock_data:
                return mock_data[symbol.upper()]
            return {"error": "Symbol not found"}, 404
        
        @app.post("/api/v1/market-data")
        async def create_market_data(data: dict):
            """创建市场数据"""
            symbol = data.get("symbol", "").upper()
            if symbol:
                mock_data[symbol] = data
                return {"message": "Data created", "symbol": symbol}
            return {"error": "Invalid data"}, 400
        
        @app.put("/api/v1/market-data/{symbol}")
        async def update_market_data(symbol: str, data: dict):
            """更新市场数据"""
            symbol = symbol.upper()
            if symbol in mock_data:
                mock_data[symbol].update(data)
                return {"message": "Data updated", "symbol": symbol}
            return {"error": "Symbol not found"}, 404
        
        @app.delete("/api/v1/market-data/{symbol}")
        async def delete_market_data(symbol: str):
            """删除市场数据"""
            symbol = symbol.upper()
            if symbol in mock_data:
                del mock_data[symbol]
                return {"message": "Data deleted", "symbol": symbol}
            return {"error": "Symbol not found"}, 404
        
        @app.get("/api/v1/symbols")
        async def list_symbols():
            """列出所有符号"""
            return {"symbols": list(mock_data.keys())}
        
        @app.get("/health")
        async def health_check():
            """健康检查"""
            return {"status": "healthy", "timestamp": datetime.now().isoformat()}
        
        return app
    
    @pytest.fixture
    def api_client(self, mock_fastapi_app):
        """创建API测试客户端"""
        if not API_FRAMEWORK_AVAILABLE:
            pytest.skip("FastAPI not available")
        return TestClient(mock_fastapi_app)
    
    @pytest.mark.skipif(not API_FRAMEWORK_AVAILABLE, reason="FastAPI not available")
    def test_get_market_data_success(self, api_client):
        """测试获取市场数据成功"""
        response = api_client.get("/api/v1/market-data/AAPL")
        assert response.status_code == 200
        
        data = response.json()
        assert data["symbol"] == "AAPL"
        assert data["price"] == 150.25
        assert "timestamp" in data
    
    @pytest.mark.skipif(not API_FRAMEWORK_AVAILABLE, reason="FastAPI not available")
    def test_get_market_data_not_found(self, api_client):
        """测试获取不存在的市场数据"""
        response = api_client.get("/api/v1/market-data/NONEXISTENT")
        # 注意：这里可能返回200但包含错误信息，或者404
        # 根据实际实现调整
        assert response.status_code in [200, 404]
    
    @pytest.mark.skipif(not API_FRAMEWORK_AVAILABLE, reason="FastAPI not available")
    def test_create_market_data_success(self, api_client):
        """测试创建市场数据成功"""
        new_data = {
            "symbol": "MSFT",
            "price": 300.75,
            "volume": 800000,
            "timestamp": "2024-01-01T11:00:00Z"
        }
        
        response = api_client.post("/api/v1/market-data", json=new_data)
        assert response.status_code == 200
        
        result = response.json()
        assert "message" in result
        assert result["symbol"] == "MSFT"
    
    @pytest.mark.skipif(not API_FRAMEWORK_AVAILABLE, reason="FastAPI not available")
    def test_health_check(self, api_client):
        """测试健康检查端点"""
        response = api_client.get("/health")
        assert response.status_code == 200
        
        data = response.json()
        assert data["status"] == "healthy"
        assert "timestamp" in data


@pytest.mark.integration
@pytest.mark.api
class TestWebSocketAPI:
    """WebSocket API端点测试"""
    
    @pytest.fixture
    def mock_websocket_manager(self):
        """创建Mock WebSocket管理器"""
        class MockWebSocketManager:
            def __init__(self):
                self.connections = {}
                self.subscriptions = {}
                self.message_count = 0
            
            async def connect_user(self, user_id, websocket):
                """连接用户"""
                self.connections[user_id] = websocket
                self.subscriptions[user_id] = set()
                return True
            
            async def disconnect_user(self, user_id):
                """断开用户连接"""
                self.connections.pop(user_id, None)
                self.subscriptions.pop(user_id, None)
                return True
            
            async def subscribe_symbol(self, user_id, symbol):
                """订阅符号"""
                if user_id in self.subscriptions:
                    self.subscriptions[user_id].add(symbol.upper())
                    return True
                return False
            
            async def unsubscribe_symbol(self, user_id, symbol):
                """取消订阅符号"""
                if user_id in self.subscriptions:
                    self.subscriptions[user_id].discard(symbol.upper())
                    return True
                return False
            
            async def broadcast_market_data(self, symbol, data):
                """广播市场数据"""
                symbol = symbol.upper()
                message_sent = 0
                
                for user_id, subscribed_symbols in self.subscriptions.items():
                    if symbol in subscribed_symbols and user_id in self.connections:
                        # 模拟发送消息
                        message_sent += 1
                        self.message_count += 1
                
                return message_sent
            
            def get_connection_count(self):
                """获取连接数量"""
                return len(self.connections)
            
            def get_subscription_count(self):
                """获取订阅数量"""
                return sum(len(subs) for subs in self.subscriptions.values())
        
        return MockWebSocketManager()
    
    @pytest.mark.asyncio
    async def test_user_connection(self, mock_websocket_manager):
        """测试用户连接"""
        mock_websocket = AsyncMock()
        
        # 测试连接
        result = await mock_websocket_manager.connect_user("user123", mock_websocket)
        assert result is True
        assert mock_websocket_manager.get_connection_count() == 1
        
        # 测试断开连接
        disconnect_result = await mock_websocket_manager.disconnect_user("user123")
        assert disconnect_result is True
        assert mock_websocket_manager.get_connection_count() == 0
    
    @pytest.mark.asyncio
    async def test_symbol_subscription(self, mock_websocket_manager):
        """测试符号订阅"""
        mock_websocket = AsyncMock()
        
        # 连接用户
        await mock_websocket_manager.connect_user("user456", mock_websocket)
        
        # 测试订阅
        subscribe_result = await mock_websocket_manager.subscribe_symbol("user456", "AAPL")
        assert subscribe_result is True
        assert mock_websocket_manager.get_subscription_count() == 1
        
        # 测试取消订阅
        unsubscribe_result = await mock_websocket_manager.unsubscribe_symbol("user456", "AAPL")
        assert unsubscribe_result is True
        assert mock_websocket_manager.get_subscription_count() == 0
    
    @pytest.mark.asyncio
    async def test_market_data_broadcast(self, mock_websocket_manager):
        """测试市场数据广播"""
        # 连接多个用户
        for i in range(3):
            mock_websocket = AsyncMock()
            await mock_websocket_manager.connect_user(f"user{i}", mock_websocket)
            await mock_websocket_manager.subscribe_symbol(f"user{i}", "AAPL")
        
        # 测试广播
        market_data = {
            "symbol": "AAPL",
            "price": 151.0,
            "timestamp": datetime.now().isoformat()
        }
        
        sent_count = await mock_websocket_manager.broadcast_market_data("AAPL", market_data)
        assert sent_count == 3  # 应该发送给3个用户
        assert mock_websocket_manager.message_count == 3


@pytest.mark.integration
@pytest.mark.api
class TestAuthenticationAPI:
    """认证API端点测试"""
    
    @pytest.fixture
    def mock_auth_service(self):
        """创建Mock认证服务"""
        class MockAuthService:
            def __init__(self):
                self.users = {
                    "testuser": {
                        "user_id": "user123",
                        "password_hash": "hashed_password",
                        "role": "user",
                        "active": True
                    },
                    "admin": {
                        "user_id": "admin123",
                        "password_hash": "admin_hash",
                        "role": "admin",
                        "active": True
                    }
                }
                self.active_tokens = {}
            
            async def authenticate_user(self, username, password):
                """用户认证"""
                user = self.users.get(username)
                if user and user["active"]:
                    # 简单的密码验证（实际应该使用哈希比较）
                    if password == "correct_password" or username == "admin":
                        return {
                            "user_id": user["user_id"],
                            "username": username,
                            "role": user["role"]
                        }
                return None
            
            async def generate_token(self, user_info):
                """生成访问令牌"""
                token = f"token_{user_info['user_id']}_{len(self.active_tokens)}"
                self.active_tokens[token] = user_info
                return {
                    "access_token": token,
                    "token_type": "Bearer",
                    "expires_in": 3600
                }
            
            async def validate_token(self, token):
                """验证令牌"""
                return self.active_tokens.get(token)
            
            async def revoke_token(self, token):
                """撤销令牌"""
                return self.active_tokens.pop(token, None) is not None
            
            async def check_permission(self, user_info, resource, action):
                """检查权限"""
                if user_info["role"] == "admin":
                    return True
                elif user_info["role"] == "user":
                    # 普通用户只能读取
                    return action in ["read", "subscribe"]
                return False
        
        return MockAuthService()
    
    @pytest.mark.asyncio
    async def test_user_login_success(self, mock_auth_service):
        """测试用户登录成功"""
        user_info = await mock_auth_service.authenticate_user("testuser", "correct_password")
        assert user_info is not None
        assert user_info["username"] == "testuser"
        assert user_info["role"] == "user"
        
        # 生成令牌
        token_info = await mock_auth_service.generate_token(user_info)
        assert "access_token" in token_info
        assert token_info["token_type"] == "Bearer"
    
    @pytest.mark.asyncio
    async def test_user_login_failure(self, mock_auth_service):
        """测试用户登录失败"""
        # 错误密码
        user_info = await mock_auth_service.authenticate_user("testuser", "wrong_password")
        assert user_info is None
        
        # 不存在的用户
        user_info = await mock_auth_service.authenticate_user("nonexistent", "any_password")
        assert user_info is None
    
    @pytest.mark.asyncio
    async def test_token_validation(self, mock_auth_service):
        """测试令牌验证"""
        # 登录并获取令牌
        user_info = await mock_auth_service.authenticate_user("testuser", "correct_password")
        token_info = await mock_auth_service.generate_token(user_info)
        token = token_info["access_token"]
        
        # 验证有效令牌
        validated_user = await mock_auth_service.validate_token(token)
        assert validated_user is not None
        assert validated_user["username"] == "testuser"
        
        # 验证无效令牌
        invalid_user = await mock_auth_service.validate_token("invalid_token")
        assert invalid_user is None


@pytest.mark.integration
@pytest.mark.api
@pytest.mark.performance
class TestAPIPerformance:
    """API性能测试"""
    
    @pytest.fixture
    def mock_performance_api(self):
        """创建性能测试用Mock API"""
        class MockPerformanceAPI:
            def __init__(self):
                self.request_count = 0
                self.response_times = []
                self.data_cache = {}
            
            async def handle_request(self, endpoint, method="GET", data=None):
                """处理请求"""
                import time
                start_time = time.time()
                
                self.request_count += 1
                
                # 模拟不同的端点处理时间
                if "market-data" in endpoint:
                    await asyncio.sleep(0.001)  # 1ms模拟数据库查询
                    response = {"symbol": "AAPL", "price": 150.0}
                elif "symbols" in endpoint:
                    await asyncio.sleep(0.002)  # 2ms模拟符号列表查询
                    response = {"symbols": ["AAPL", "GOOGL", "MSFT"]}
                elif "health" in endpoint:
                    response = {"status": "healthy"}
                else:
                    response = {"error": "Not found"}
                
                execution_time = time.time() - start_time
                self.response_times.append(execution_time)
                
                return response, execution_time
            
            async def stress_test(self, concurrent_requests):
                """压力测试"""
                async def single_request():
                    return await self.handle_request("/api/v1/market-data/AAPL")
                
                start_time = time.time()
                tasks = [single_request() for _ in range(concurrent_requests)]
                results = await asyncio.gather(*tasks, return_exceptions=True)
                total_time = time.time() - start_time
                
                successful_requests = len([r for r in results if not isinstance(r, Exception)])
                return successful_requests, total_time
            
            def get_average_response_time(self):
                """获取平均响应时间"""
                if self.response_times:
                    return sum(self.response_times) / len(self.response_times)
                return 0
        
        return MockPerformanceAPI()
    
    @pytest.mark.asyncio
    async def test_single_request_performance(self, mock_performance_api):
        """测试单个请求性能"""
        response, response_time = await mock_performance_api.handle_request("/api/v1/market-data/AAPL")
        
        assert response["symbol"] == "AAPL"
        assert response_time > 0
        # 性能断言：单个请求应在10ms内完成
        assert response_time < 0.01, f"Request took {response_time:.3f}s"
    
    @pytest.mark.asyncio
    async def test_concurrent_requests_performance(self, mock_performance_api):
        """测试并发请求性能"""
        concurrent_count = 50
        successful_count, total_time = await mock_performance_api.stress_test(concurrent_count)
        
        assert successful_count == concurrent_count
        assert total_time > 0
        # 性能断言：50个并发请求应在1秒内完成
        assert total_time < 1.0, f"Concurrent requests took {total_time:.3f}s"
        
        # 计算QPS
        qps = successful_count / total_time
        assert qps > 50, f"QPS too low: {qps:.2f}"
    
    @pytest.mark.benchmark
    def test_api_endpoint_benchmark(self, benchmark):
        """API端点基准测试"""
        def api_operation():
            # 模拟API操作
            data = {"symbol": "AAPL", "price": 150.0}
            processed = {}
            for key, value in data.items():
                processed[key.upper()] = value
            return processed
        
        result = benchmark(api_operation)
        assert result["SYMBOL"] == "AAPL"
        assert result["PRICE"] == 150.0
